#include "m26.h"
#include "stm32f10x.h"
#include "system.h"
#include "usart.h"
#include "at.h"
#include "event_flag.h"
#include "string_util.h"
#include <stdint.h>
#include "led.h"

/**< AT指令回显状态 */
typedef enum{
	ATE_Disable = 0,
	ATE_Enable  =1
}ATE_State;


/**< 结果码显示模式 */
typedef enum{
	ATQ_Disable  = 0,
	ATQ_Enable   = 1
}ATQ_State;


/**<  */
typedef enum{
	ATV_Number  = 0,
	ATV_Text    = 1
}ATV_State;


static ATE_State  ATEState  = ATE_Enable;
static ATQ_State  ATQState  = ATQ_Enable;
static ATV_State  ATVState  = ATV_Text;



void M26_InitPort(void)
{
  GPIO_InitTypeDef GPIOConfig;

  RCC_APB2PeriphClockCmd(M26_GPIO_CLK, ENABLE);

  GPIOConfig.GPIO_Mode   = GPIO_Mode_Out_PP;
  GPIOConfig.GPIO_Speed  = GPIO_Speed_50MHz;
  GPIOConfig.GPIO_Pin    = M26_POWER_Pin | M26_PWRKEY_Pin;
  GPIO_Init(M26_GPIO, &GPIOConfig);
}


void M26_EnablePower(void)
{
  GPIO_SetBits(M26_GPIO, M26_POWER_Pin);
}


void M26_DisablePower(void)
{
  GPIO_ResetBits(M26_GPIO, M26_POWER_Pin);
}


void M26_EnablePwk(void)
{
  GPIO_SetBits(M26_GPIO, M26_PWRKEY_Pin);
}


void M26_DisablePwk(void)
{
  GPIO_ResetBits(M26_GPIO, M26_PWRKEY_Pin);
}



/**@brief   软件关机
 * 
 *
 * @param
 * @return
 * @note
 */
void M26_Shutdown(void)
{
ATDebugln("Shutdonw...");	
	M26_EnablePwk();
	sendAtCmd("AT+QPOWN=1");
	delayMs(SHUTDOWN_FADE_TIME);
}




/**@brief  硬件关机
 * 
 *
 * @param
 * @return
 * @note
 */
void M26_PowerOff(void)
{
ATDebugln("Poweroff...");	
	M26_DisablePwk();
	delayMs(PWK_DISABLE_FADE_TIME);
	delayMs(POWER_OFF_FADE_TIME);
	M26_DisablePower();
ATDebugln("Power down");	
}





/**@brief    OnSetup
 * 
 *
 * @param
 * @return
 * @note
 */
AT_Echo  OnSetup(void)
{
	AT_Echo result  ;
	uint32_t baudRate;
	uint8_t  tryCnt  = ON_SETUP_RETRY;
	
	
//	while(1){
//		WaitAtOk(20);
//	}
	
	WaitReady(100);
				
	
	while(tryCnt--){
		LED_On(LED1);
		result  = WaitAtOk(20);
		LED_Off(LED1);
		if(result != AT_No_Error){
			ATDebugln("Wait at error:%d", result);
			return AT_Error;
		}
		ATDebugln("Wait AT ok");
		
		
		result  = QueryBaudRate(&baudRate);
		if( result != AT_No_Error ){
			ATDebugln("Query baud rate error:%d", result);
			return AT_Error;	
		}
		
		if(baudRate != 115200){
			result  = ConfigBaudRate(115200);
			if( result != AT_No_Error ){
				ATDebugln("Config baud rate error:%d", result);
				return AT_Error;	
			}		
		}
		
//		result  = SaveUserConfiguration(0);
//		if(result != AT_No_Error){
//			ATDebugln("Save user configuration error:%d", result);
//		}


		return AT_No_Error;
	}

}






/**@brief  启用模块
 * 
 *
 * @param
 * @return
 * @note
 */
int M26_Boot(void)
{
ATDebugln("Booting...");	
	M26_DisablePwk();
	delayMs(PWK_DISABLE_FADE_TIME);	
	M26_EnablePwk();
	delayMs(PWK_ENABLE_HOLD_TIME);
	
//	if( OnSetup() == AT_No_Error){
//		return 1;
//	}
//	
//	ATDebugln("On setup failed");
	return 1;
}





/**@brief   重启模块
 * 
 *
 * @param
 * @return
 * @note
 */
void M26_Reboot(void)
{
ATDebugln("Rebooting...");	
	M26_Shutdown();
	delayMs(BOOT_AFTER_SHUTDOWN);
	M26_Boot();
}


AT_Echo PendAt(uint32_t timeout)
{
	uint16_t cnt  = timeout /10;
	while(cnt--){
		delayMs(10);		
		if(GetEventFlag(EVENT_FLAG_RX)){
			CleanEventFlag(EVENT_FLAG_RX);
			return AT_No_Error;
		}
	}	
		
	return AT_Timeout;
}


/**@brief
 * 
 *
 * @param
 * @return
 * @note
 */
AT_Echo PendBegintWith(char* keyWord, uint16_t timeout)
{	
	if( PendAt(timeout) == AT_No_Error){
		if( strBeginWith((char*)Usart1_RxBuf, keyWord) ){
			return AT_No_Error;
		}
		
		return AT_Not_Match;
	}
	else{
dump( (char*)Usart1_RxBuf );		
	}
	
	return AT_Timeout;
}


/**@brief
 * 
 *
 * @param
 * @return
 * @note
 */
AT_Echo PendContain(char* keyWord, uint16_t timeout)
{
	if( PendAt(timeout) == AT_No_Error){
		if( strstr( (char*)Usart1_RxBuf, keyWord ) ){
			return AT_No_Error;
		}
		
		dump( (char*)Usart1_RxBuf );
		return AT_Not_Match;
	}
	else{
dump( (char*)Usart1_RxBuf );		
	}	
	
	
	return AT_Timeout;
}



/**@brief
 * 
 *
 * @param
 * @return
 * @note
 */
AT_Echo PendExecResult(uint32_t timeout)
{
	if( PendAt(timeout) == AT_No_Error){
		if( strstr( (char*)Usart1_RxBuf, "OK" ) ){
			return AT_No_Error;
		}
		else if( strstr( (char*)Usart1_RxBuf, "ERROR" ) ){
			return AT_Error;
		}
		return AT_Not_Match;
	}
	
	return AT_Timeout;	
}






/**@brief
 * 
 *
 * @param
 * @return
 * @note
 */
AT_Echo WaitAtOk(uint16_t retry)
{	
	while(retry--){
		sendAtCmd("AT");
	
		if( PendContain("OK", 500) == AT_No_Error){
			return AT_No_Error;
		}
	}	
	
	return AT_Timeout;
}




AT_Echo WaitReady(uint16_t retry)
{	
	PendAt(300);
	
	while(retry--){
		if(PendContain("RDY", 300) == AT_No_Error){
			return AT_No_Error;
		}
	}
	
	return AT_Timeout;
}




AT_Echo WaitWord(char* word, uint16_t retry)
{
	while(retry--){
		if( PendContain(word, 300) == AT_No_Error){
			return AT_No_Error;
		}
	}
	
	return AT_Timeout;
}




/**@brief   查询M26波特率
 * 
 *
 * @param
 * @return
 * @note
 */
AT_Echo QueryBaudRate(uint32_t* baudRate)
{
	const char*  token;
	int scan_result;
	
	sendAtCmd("AT+IPR?");
	if( PendAt(300) == AT_No_Error){
		
		token  = strstr( (char*)Usart1_RxBuf,  "+IPR:");

		if( token ){			
			if( sscanf( token, "+IPR: %u", baudRate ) == 1){
				return AT_No_Error ;
			}
			else{
				return AT_Param_Fail;
			}
		}
		
		return AT_Not_Match;
	}
	
	return AT_Timeout;
}



/**@brief  配置M26波特率
 * 
 *
 * @param
 * @return
 * @note
 */
AT_Echo ConfigBaudRate(uint32_t baudRate)
{
	char cmd[16]  = {0};
	
	sprintf(cmd, "AT+IPR=%u", baudRate);
	
	sendAtCmd(cmd);
	return (PendExecResult(300));
}



/**@brief  配置结果码显示模式
 * 
 *
 * @param
 * @return
 * @note
 */
AT_Echo ConfigATQ(int n)
{
	if(n == 1){
		sendAtCmd("ATQ1");
	}
	else{
		sendAtCmd("ATQ0");
	}
}




/**@brief WriteBaudRate
 * 
 *
 * @param
 * @return
 * @note
 */
AT_Echo SaveUserConfiguration(int n)
{
	char cmd[16]  = {0};
	
	sprintf(cmd, "AT&W%d", n);
	
	sendAtCmd(cmd);
	
	return (PendExecResult(300));
}



/**@brief   查询SIM卡状态
 * 
 *
 * @param
 * @return
 * @note
 */
AT_Echo QuerySIMStatus()
{
	sendAtCmd("AT+CPIN?");
	
	return PendContain("READY", 300);
}
	


/**@brief  查询信号质量
 * 
 *
 * @param
 * @return
 * @note
 */
AT_Echo QuerySignalQuality(int* n, int* stat)
{
	AT_Echo result  ;
	sendAtCmd("AT+CSQ");
	
	
	result  = PendExecResult(300) ;
	if( result == AT_No_Error){
		ATDebugln("Pend csq exec result");
	}
	else{
		ATDebugln("Pend csq exec:%d", result);
	}
	
	if(PendAt(300)){
		
		if(sscanf( (char*)Usart1_RxBuf, "\r\n+CSQ: %d,%d", n, stat) == 2){
			return AT_No_Error;
		}
		else{
			dump((char*)Usart1_RxBuf);
			return AT_Param_Fail;
		}
	}
	else{
		return AT_Timeout;
	}
}



/**@brief  查询有效信号质量
 * 
 *
 * @param
 * @return
 * @note
 */
AT_Echo QueryValidSignalQuality(int* n, int* stat)
{
	uint16_t timeout  = SQ_RETRY;
	int sq_n     = 0;
	int sq_stat  = 0;
	
	while(timeout--){
		if( QuerySignalQuality(&sq_n, &sq_stat) == AT_No_Error){
			if( sq_n >= SQ_MIN  && sq_n <= SQ_MAX){
				*n  = sq_n;
				*stat  = sq_stat;
				return AT_No_Error;
			}
		}
		delayMs(SQ_INTERVAL);
	}
	
	return AT_Timeout;	
}



/**@brief  查询模块GSM网络注册状态
 * 
 *
 * @param
 * @return
 * @note
 */
AT_Echo QueryGSMSNetStatus( int* n, int* stat)
{
	sendAtCmd("AT+CREG?");
	if( PendAt(300) ){
		
		if( sscanf( (char*)Usart1_RxBuf, "AT+CREG: %d,%d", n, stat ) == 2){
			return AT_No_Error;
		}
		else{
			return AT_Param_Fail;
		}
	}
	else{
		return AT_Timeout;
	}
}


/**@brief  配置GSM网络
 * 
 *
 * @param
 * @return
 * @note
 */
AT_Echo ConfigGSMNet(int n)
{
	char cmd[16];
	
	sprintf(cmd, "AT+CREG=%d", n);
	
	sendAtCmd(cmd);
	
	return PendExecResult(300);
}




/**@brief  查询模块GPRS网络注册状态
 * 
 *
 * @param
 * @return
 * @note
 */
AT_Echo QueryGPRSNetStatus( int* n, int* stat)
{
	sendAtCmd("AT+CGREG?");
	if( PendAt(300) ){
		
		if( sscanf((char*)Usart1_RxBuf, "AT+CGREG: %d,%d", n, stat ) == 2){
			return AT_No_Error;
		}
		else{
			return AT_Param_Fail;
		}
	}
	else{
		return AT_Timeout;
	}
}


/**@brief  配置GPRS网络
 * 
 *
 * @param
 * @return
 * @note
 */
AT_Echo ConfigGPRSNet(int n)
{
	char cmd[16];
	
	sprintf(cmd, "AT+CGREG=%d", n);
	
	sendAtCmd(cmd);
	
	return PendExecResult(300);
}



/**@brief  查询前置场景
 * 
 *
 * @param
 * @return
 * @note
 */
AT_Echo QueryFrontScene(int *id, int* chn)
{
	sendAtCmd("AT_QIFGCNT?");
	
	if(PendAt(300))
	{
		if( sscanf( (char*)Usart1_RxBuf, "+QIFGCNT: id,chn") == 2){
			return AT_No_Error;
		}
		else{
			return AT_Param_Fail;
		}
	}
	else{
		return AT_Timeout;
	}		
}



/**@brief  配置GPRS场景
 * 
 *
 * @param
 * @return
 * @note
 */

AT_Echo ConfigScene(int id)
{
	char cmd[16];
	
	sprintf(cmd, "AT+QIFGCNT=%d", id);
	sendAtCmd(cmd);	
	return PendExecResult(300);
}



/**@brief  配置连接模式
 * 
 *
 * @param
 * @return
 * @note
 */
AT_Echo ConfigAP(int mode, char* apn)
{
	char cmd[32];
	
	sprintf(cmd,"AT_QICSGP=%d,\"%s\"",mode,apn);
	sendAtCmd("cmd");
	return PendExecResult(300);
}




/**@brief  设置数据传输模式
 * 
 *
 * @param
 * @return
 * @note
 */
AT_Echo ConfigTransmissionMode(int mode)
{
	char cmd[32];
	
	sprintf(cmd, "AT+QIMODE=%d",mode);
	sendAtCmd("cmd");
	return PendExecResult(300);	
}



/**@brief   去激活场景
 * 
 *
 * @param
 * @return
 * @note
 */
AT_Echo DeactScene(void)
{
	sendAtCmd("AT+QIDEACT");
	return PendExecResult(40000);
}




/**@brief   去激活场景
 * 
 *
 * @param
 * @return
 * @note
 */
AT_Echo ActiveScene(void)
{
	sendAtCmd("AT+QIDEACT");
	return PendExecResult(150000);
}




/**@brief   启动任务
 * 
 *
 * @param
 * @return
 * @note
 */
AT_Echo  RegisterApp(char* apn, char* username, char* passwd)
{
	char cmd[54]  = "AT+QIREGAPP=";
	
	if(username &&  passwd){
		sprintf(cmd, "AT+QIREGAPP=\"%s\",\"%s\",\"%s\"", apn, username, passwd);	
	}
	else{
		sprintf(cmd, "AT+QIREGAPP=\"%s\"", apn);
		strcat(cmd, ",\"\",\"\"");
	}
	
	sendAtCmd(cmd);
	return (PendExecResult(300));
}




/**@brief  
 * 
 *
 * @param
 * @return
 * @note
 */
AT_Echo TCP_IP_Reach_Process(void)
{
	int n  = 0;
	int s  = 0;
	
	AT_Echo result;
	
ATDebugln("Init TCP/IP process......");	
	
	
	/** SIM */
	result  =  QuerySIMStatus();
	if( result != AT_No_Error) {	
		ATDebugln("Query SIM status error:%d", result);
		return AT_Error;
	}
	
	/** Signal quality */
	result  = QueryValidSignalQuality(&n, &s);
	if( result != AT_No_Error){
		ATDebugln("Query signal quality error:%d", result);
		return AT_Error;
	}
	
	
	/** GPRS net */
	result  = ConfigGPRSNet(1);
	if( result != AT_No_Error){
		ATDebugln("Config GPRS net error:%d", result);
		return AT_Error;
	}
	
	
	/** Front scene */
	result  = ConfigScene(0);
	if( result != AT_No_Error){
		ATDebugln("Config scene error:%d", result);
		return AT_Error;
	}
	
	
	/** AP */
	result  = ConfigAP(1,"CMNET");
	if( result != AT_No_Error) {
		ATDebugln("Config ap error:%d", result);
		return AT_Error;
	}
	
	
	/** Transmission mode */
	result  = ConfigTransmissionMode(0);
	if( result != AT_No_Error){
		ATDebugln("Config transmission mode error:%d", result);
		return AT_Error;
	}
	
	
	/** Deact */
	result  = DeactScene();
	if( result != AT_No_Error){
		ATDebugln("Deact scene error:%d",result);
		return AT_Error;
	}
	
	
	/** Register application */
	result  = RegisterApp("CMNET", NULL, NULL);
	if( result != AT_No_Error){
		ATDebugln("Register app error:%d", result);
		return AT_Error;
	}
	
	
	/** Active */
	result  = ActiveScene();
	if( result != AT_No_Error){
		ATDebugln("Active scene error:%d", result);
		return AT_Error;
	}
	
	result  = Connect(1, "112.80.5.117", 5683);
	if(result != AT_No_Error){
		ATDebugln("Connect error:%d", result);
		return AT_Error;
	}
	
	
	return AT_No_Error;
}


/**@brief  Open tcp/ip connection
 * 
 *
 * @param
 * @return
 * @note
 */
AT_Echo Connect(int type, char* ip, int port)
{
	char cmd[64];
	
	sprintf(cmd, "AT+QIOPEN=\"%s\",\"%s\",%d",
		type == 0 ? "TCP" : "UDP", ip, port);
	
	sendAtCmd(cmd);
	return (PendExecResult(300));
}



/**@brief 查询连接状态
 * 
 *
 * @param
 * @return
 * @note
 */
AT_Echo QueryIPState(int* n)
{
	const char * token ;
	sendAtCmd("AT+QISTATE");
	
	if(PendAt(300)){
		token  = strstr( (char*)Usart1_RxBuf, ":");
		if(token){
			switch(token[2]){
				case 'I':
					switch(token[7]){
						/** IP INITIAL */
						case 'I':  *n = '0'; break;
						/** IP START or IP STATUS */
						case 'A':  *n = (token[8] == 'R' ? '1' : '5'); break;
						/** IP CONFIG */
						case 'C':  *n  = '2'; break;
						/** IP IND */
						case 'D':  *n  = '3'; break;
						/** IP GPRSACT */
						case 'R':  *n  = '4'; break;
						/** IP CLOSE */
						case 'O':  *n  = '7';
						
					}
					break;
				
				case 'T':
					*n  = '6';
					break;
				
				case 'U':
					*n  = '6';
					break;
				
				case 'C':
					*n  = '8';
					break;
				
				case 'P':
					*n  = '9';
					break;
				
				default:
					*n  = -1;
					return AT_Param_Fail;
					break;
			}
		}
		else{
			return AT_Param_Fail;
		}
	}
	else{
		return AT_Timeout;
	}
}



AT_Echo ParseGSMStatus(char* str, int*n, int* stat)
{	
	int result  = sscanf(str, "+CREG: %d,%d", n, stat);
	if(result == 2){
		return AT_No_Error;
	}
	else if(result == 1){
		*stat  = *n;
		return AT_No_Error;
	}
	
	return AT_Param_Fail;
}




AT_Echo ParseGPRSStatus(char* str, int* n, int* stat)
{
	int result  = sscanf(str, "+CGREG: %d,%d", n, stat);
	if(result == 2){
		return AT_No_Error;
	}
	else if(result == 1){
		*stat  = *n;
		return AT_No_Error;
	}
	
	return AT_Param_Fail;	
}






/**@brief  发送
 * 
 *
 * @param
 * @return
 * @note
 */
AT_Echo Send(uint8_t* buf, uint16_t size)
{
	char cmd[16];
	sprintf(cmd, "AT+QISEND=%d", size);
	sendAtCmd(cmd);
	
	PendAt(300);
	
	sendAtData(buf, size);
	
	return (PendContain("SEND OK", 300));
}



void WhateverGotoInternet(void)
{
	static uint32_t    boot_interval  = (5*60*1000000);
	static uint32_t    lastBootTick  = 0;
	uint32_t  tmpTick ;
	
	RETRY:
	
	tmpTick  = getSystemTick();
	
	if( (tmpTick - lastBootTick) >= boot_interval){	
		
		M26_Reboot();
		
		lastBootTick  = getSystemTick();
		if(boot_interval < (60*60*1000000)){
			boot_interval <<= 2;
		}
		
		if(TCP_IP_Reach_Process() == AT_No_Error){
			boot_interval  = (5*60*1000000);
			return ;
		}
		else{
			delayMs(boot_interval);
		}
	}
	else{
		delayMs(boot_interval - (tmpTick - lastBootTick));
	}
	
	goto RETRY;
}


